#ifndef CODEEDITORPRIVATE_H
#define CODEEDITORPRIVATE_H

#include "CodeEditor.h"
#include "IFindSupport.h"
#include "CodeEditorAnimator.h"

#include "Settings/DisplaySettings.h"
#include "Settings/FontSettings.h"

#include <QtCore>
#include <QtGui>

namespace CodeEdit {

class FileDocument;
class CodeEditorActionHandler;

namespace Internal {

struct CodeEditorPrivateHighlightBlocks
{
    QList<int> open;
    QList<int> close;
    QList<int> visualIndent;
    inline int count() const { return visualIndent.size(); }
    inline bool isEmpty() const { return open.isEmpty() || close.isEmpty() || visualIndent.isEmpty(); }
    inline bool operator==(const CodeEditorPrivateHighlightBlocks &rhs) const {
        return (open == rhs.open && close == rhs.close && visualIndent == rhs.visualIndent);
    }
    inline bool operator!=(const CodeEditorPrivateHighlightBlocks &rhs) const {
        return !(*this == rhs);
    }
};

class CodeEditorPrivate
{
private:
    // disable copy constructor and assignment operator
    CodeEditorPrivate(const CodeEditorPrivate&);
    CodeEditorPrivate &operator=(const CodeEditorPrivate&);

public:
    CodeEditorPrivate();
    ~CodeEditorPrivate();

    void setupBasicEditActions(CodeEditorActionHandler *actionHandler);
    void setupDocumentSignals(FileDocument *document);
    void updateLineSelectionColor();

    void print(QPrinter *printer);

    //! [zoom]
    int fontZoom;
    static int fontZoomMin;
    static int fontZoomMax;

    QTextBlock firstVisible;
    int lastScrollPos;
    int lineNumber;

    CodeEditor *q;
    bool contentsChanged;
    bool lastCursorChangeWasInteresting;

    QList<QTextEdit::ExtraSelection> syntaxHighlighterSelections;
    QTextEdit::ExtraSelection lineSelection;

    FileDocument *document;
    QByteArray tempState;
    QByteArray tempNavigationState;

    QString displayName;
    bool parenthesesMatchingEnabled;
    bool autoParenthesesEnabled;
    QTimer *updateTimer;

    // parentheses matcher
    bool formatRange;
    QTextCharFormat matchFormat;
    QTextCharFormat mismatchFormat;
    QTextCharFormat rangeFormat;
    QTimer *parenthesesMatchingTimer;
    // end parentheses matcher

    QWidget *extraArea;

    DisplaySettings displaySettings;
    FontSettings fontSettings;

    int extraAreaSelectionAnchorBlockNumber;
    int extraAreaToggleMarkBlockNumber;
    int extraAreaHighlightFoldedBlockNumber;

    QBasicTimer foldedBlockTimer;
    int visibleFoldedBlockNumber;
    int suggestedVisibleFoldedBlockNumber;
    void clearVisibleFoldedBlock();
    bool mouseOnFoldedMarker;
    void foldLicenseHeader();

    QBasicTimer autoScrollTimer;
    void updateMarksLineNumber();
    void updateMarksBlock(const QTextBlock &block);
    uint marksVisible : 1;
    uint codeFoldingVisible : 1;
    uint codeFoldingSupported : 1;
    uint mouseNavigationEnabled : 1;
    uint revisionsVisible : 1;
    uint lineNumbersVisible : 1;
    uint highlightCurrentLine : 1;
    uint requestMarkEnabled : 1;
    uint lineSeparatorsAllowed : 1;
    int visibleWrapColumn;

    QTextCharFormat ifdefedOutFormat;

    QRegExp searchExpr;
    Find::IFindSupport::FindFlags findFlags;
    QTextCharFormat searchResultFormat;
    QTextCharFormat searchScopeFormat;
    QTextCharFormat currentLineFormat;
    QTextCharFormat currentLineNumberFormat;
    void highlightSearchResults(const QTextBlock &block, CodeEditorOverlay *overlay);

    QObject *actionHack;

    QList<QTextEdit::ExtraSelection> extraSelections[CodeEditor::NExtraSelectionKinds];

    // block selection mode
    bool inBlockSelectionMode;
    bool lastEventWasBlockSelectionEvent;
    int blockSelectionExtraX;
    void clearBlockSelection();
    QString copyBlockSelection();
    void removeBlockSelection(const QString &text = QString());
    bool moveLineUndoHack;

    QTextCursor findScopeStart;
    QTextCursor findScopeEnd;
    int findScopeVerticalBlockSelection;
    QTextCursor selectBlockAnchor;

    void moveCursorVisible(bool ensureVisible = true);

    int visualIndent(const QTextBlock &block) const;
    CodeEditorPrivateHighlightBlocks highlightBlocksInfo;
    QTimer *highlightBlocksTimer;

    QPointer<CodeEditorAnimator> animator;
    int cursorBlockNumber;

    bool inKeyPressEvent;
};

} // namespace Internal
} // namespace CodeEdit

#endif // CODEEDITORPRIVATE_H
